#include <stdio.h>
#include <sys/socket.h> //socket()
#include <sys/types.h>  //
#include <netinet/in.h> //struct sockaddr_in
#include <errno.h>      //perror()
#include <string.h>     //memset()
#include <unistd.h>     //close()
#include <arpa/inet.h>  //inet_addr

uint16_t listenPort = 50000;

int main(int argn, char **argv)
{
    printf("start create tcp listerner socket\n");

    //socket() https://man7.org/linux/man-pages/man2/socket.2.html
    int domain = AF_INET;       //AF_INET IPv4 | AF_INET6 IPv6
    int type = SOCK_STREAM;     // TCP使用的Socket样式：SOCK_STREAM | UDP使用的socket样式：SOCK_DGRAM
    int protocol = IPPROTO_TCP; // IPPROTO_IP:0 默认协议 | IPPROTO_TCP TCP协议 | IPPROTO_UDP UDP协议 注意：协议类型需要与socket样式匹配
    int listener = socket(domain, type, protocol);
    if (listener == -1)
    {
        printf("Can't create listener socket\n");
        perror("perror：");
        return -1;
    }

    printf("create tcp listerner socket [%d]\n", listener);

    printf("listerner socket [%d] start bind [%d]\n", listener, listenPort);

    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serverAddr.sin_port = htons(listenPort); //监听50000端口
    serverAddr.sin_family = AF_INET;         //IPv4

    //int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    int bindRet = bind(listener, (sockaddr *)&serverAddr, sizeof(serverAddr));
    if (bindRet == -1)
    {
        printf("listerner socket [%d] Can't bind listener socket\n", listener);
        perror("perror：");
        close(listener);
        return -1;
    }

    printf("listerner socket [%d] start listener[%d]\n", listener, listenPort);

    //int listen(int socket, int backlog);
    int backlog = 1;
    int listenRet = listen(listener, 128); // 只接入一个连接
    if (listenRet == -1)
    {
        printf("listerner socket [%d] listener socket error\n", listener);
        perror("perror：");
        close(listener);
        return -1;
    }

    printf("listerner socket [%d] succeed listener[%d]\n", listener, listenPort);

    //超时时间
    struct timeval tv;
    

    //声明集合
    int maxsock = listener; //目前只要一个socket,不需要找到最大的
    fd_set server_fd_set;

    while (1)
    {
        tv.tv_sec = 30;
        tv.tv_usec = 0;

        FD_ZERO(&server_fd_set);          //清空集合
        FD_SET(listener, &server_fd_set); //管理
        /*
        int select(
            int nfds,
            fd_set *readfds,
            fd_set *writefds,
            fd_set *exceptfds,
            struct timeval *timeout
        );
        */
        printf("timeout:[%d,%d]",tv.tv_sec,tv.tv_usec);
        int selectRet = select(maxsock + 1, &server_fd_set, NULL, NULL, &tv);
        if (selectRet < 0)
        {
            printf("select error\n");
        }
        else if (selectRet == 0)
        {
            printf("select timeout\n");
            continue;
        }
        else
        {
            printf("select accept\n");
            if (FD_ISSET(listener, &server_fd_set))
            { // 判断是否是listener触发
                struct sockaddr_in clientAddr;
                unsigned int nLen = sizeof(sockaddr_in);
                printf("listerner socket [%d] start accept %d\n", listener, listenPort);
                int client = accept(listener, (sockaddr *)&clientAddr, &nLen);
                if (client < 0)
                {
                    printf("listerner socket [%d] accept error\n", listener);
                    close(listener);
                    return -1;
                }

                printf("input [SOCKET: %d, IP：%s,  PORT：%d]\n", client, inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
            }
        }
        printf("select end\n");
    }

    close(listener);
    return 0;
}
